
#ifndef ARMY_HPP
#define ARMY_HPP

#include "iarmy.hpp"
#include "antlist.hpp"
#include "igeneral.hpp"
class army:
  public iarmy
{
public:

  army()
    : _rows(-1)
    , _cols(-1)
  {
  }

  virtual ~army() 
  {
  }

  virtual void initialize(int rows, int cols)
  {
    _rows = rows;
    _cols = cols;
    _area= location(rows, cols);
    _wavemap.create(_rows, _cols, &_not_available);
    _antlist.create(&_wavemap);
  }

  virtual size_t size() const
  {
    return _antlist.size();
  }

  virtual void reconnaissance( igeneral* g)
  {
    
    _step = 0;
    _target_antlist.clear();
    _target_wavemap.clear();

    _not_available = g->istudy();
    _not_available |= g->water();

    
    const std::vector<location>& foodlist = g->foodlist();
    std::vector<location>::const_iterator beg = foodlist.begin(); 
    std::vector<location>::const_iterator end = foodlist.end();
    for ( ;beg!=end; ++beg )
    {
      
      target_wavemap::iterator witr = _target_wavemap.insert( std::make_pair(*beg, wavemap() ) ).first;
      target_antlist::iterator aitr = _target_antlist.insert( std::make_pair(*beg, antlist() ) ).first;

      witr->second.create(_rows, _cols, &_not_available);
      aitr->second.create( &witr->second);

      witr->second.set(*beg, 1, 50);

     /* witr->second.set(*beg);
      witr->second.begin_drive();
      for (int i=0; i < 50 && !_wavemap; ++i)
        witr->second.drive_wave();*/
      const std::vector<item>& ants = g->antlist();
      std::vector<item>::const_iterator itr = ants.begin();
      int count = 0;
      for ( ; itr!= ants.end(); ++itr )
      {
        if ( itr->value == 0 )
        {
          if ( aitr->second.add( static_cast<const location&>(*itr) ) )
            ++count;
        }
        
      }
      if ( count == 0)
      {
        _target_antlist.erase(aitr);
        _target_wavemap.erase(witr);
      }
    }

    /*
    _wavemap = wavemap();
    _wavemap.create(_rows, _cols, &_available, 0, 0);
     beg = foodlist.begin(); 
    end = foodlist.end();
    for ( ;beg!=end; ++beg )
      _wavemap.set( *beg, 1, 150 );
    */

    
/*    
    _wavemap.set( g->food() );

    if (!_wavemap)
      _wavemap.begin_drive();
    
    for (int i=0; i < 50 && !_wavemap; ++i)
      _wavemap.drive_wave();
    */
    
/*
    _antlist.create(&_wavemap);
    
    const std::vector<item>& ants = g->antlist();
    std::vector<item>::const_iterator itr = ants.begin();
    for ( ; itr!= ants.end(); ++itr)
    {
      if ( itr->value == 0 )
        _antlist.add( static_cast<const location&>(*itr) );
    }
    */
    /*
    not_available = g->myants();
    not_available.inverse();
    _available &= not_available;
    */
    

    std::vector<advice>& forces = g->forces();
    advice adv = candidate();
    while (adv)
    {
      
      std::vector<advice>::iterator itr = std::lower_bound(forces.begin(), forces.end(), adv);
      if ( itr->priority < 0 )
        *itr = adv;
      adv = candidate();
      committed( adv, location::move(adv, adv.direction, _area) );
    }
   
   
  }

  // Возвращаем кандитата, самого важного с наибольшим весом 
  virtual advice candidate()
  {
    
    advice adv;
    /*item itm1 = _antlist.front();
    static_cast<location&>(adv) = itm1;
    adv.weight = itm1.value;
    adv.direction = _wavemap.direction(adv);
    
    return adv;*/
    
    
    
    if (!_target_antlist.empty() )
    {
      target_antlist::iterator itr= _target_antlist.begin();
      
      //std::cerr << _step << ":" << _target_antlist.size() << " > "<< _step % _target_antlist.size()   << std::endl;
      /*if (_target_antlist.size() > 1 )*/
      std::advance(itr, _step % _target_antlist.size()  );
      item itm = itr->second.front();
      if (itm)
      {
        static_cast<location&>(adv) = itm;
        adv.weight = itm.value;
        adv.direction = itr->second.get_wavemap()->direction(adv);
      }
    }
    else
    {
      target_antlist::iterator beg = _target_antlist.begin();
      target_antlist::iterator end = _target_antlist.end();
    }
    
    ++_step;
    return adv;
  
  }
  
  
  virtual advice variant( location loc )
  {
    return advice();
  }
  
  virtual void committed( location from, location to)
  {
    /*
    _antlist.remove(from);
    
    _available.reset(to);
    _available.set(from);
    
    */
    //_antlist.remove(from);
    target_antlist::iterator beg = _target_antlist.begin();
    target_antlist::iterator end = _target_antlist.end();
    for (;beg!=end; )
    {
      beg->second.remove(from);
      if ( beg->second.size() == 0 )
        _target_antlist.erase(beg++);
      else
        ++beg;
    }
  }

  void show(std::ostream& os)
  {
    /*
    _available.show(os, "ARMY AVALIBE");
    _wavemap.show(os, "ARMY FOOD WAVE");
    */
  }

protected:
  int _step;
  int _rows;
  int _cols;
  location _area;
  antlist _antlist;
  wavemap _wavemap;
  bitmap  _not_available;
  
  
  typedef std::map<location, wavemap> target_wavemap;
  typedef std::map<location, antlist> target_antlist;
  target_antlist _target_antlist;
  target_wavemap _target_wavemap;
  
};

#endif
